<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="rDWhy" id="rDWhy"><span data-lake-id="u02e28696" id="u02e28696">典型回答</span></h1>
  <p data-lake-id="u86855280" id="u86855280"><br></p>
  <p data-lake-id="u4c72082c" id="u4c72082c"><span data-lake-id="ue9706b6e" id="ue9706b6e">jstack用于生成java虚拟机当前时刻的线程快照。</span></p>
  <p data-lake-id="u28f0c1b0" id="u28f0c1b0"><span data-lake-id="ucb4ea465" id="ucb4ea465">​</span><br></p>
  <blockquote data-lake-id="u1f3cd111" id="u1f3cd111">
   <p data-lake-id="u66b6d50b" id="u66b6d50b"><span data-lake-id="uafae1f87" id="uafae1f87">线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合</span></p>
  </blockquote>
  <p data-lake-id="u88ce6c56" id="u88ce6c56"><span data-lake-id="uc583546d" id="uc583546d">​</span><br></p>
  <p data-lake-id="ubf6dd938" id="ubf6dd938"><span data-lake-id="u36764aff" id="u36764aff">生成线程快照的主要目的是定位线程出现长时间停顿的原因，如线程间死锁、死循环、请求外部资源导致的长时间等待等。 </span></p>
  <p data-lake-id="ua5c6418e" id="ua5c6418e"><span data-lake-id="u69385766" id="u69385766">​</span><br></p>
  <p data-lake-id="u25f61e7b" id="u25f61e7b"><span data-lake-id="u07391e7f" id="u07391e7f">线程出现停顿的时候通过jstack来查看各个线程的调用堆栈，就可以知道没有响应的线程到底在后台做什么事情，或者等待什么资源。 </span></p>
  <p data-lake-id="ua346a41f" id="ua346a41f"><br></p>
  <h1 data-lake-id="hXeiF" id="hXeiF"><span data-lake-id="u758db533" id="u758db533">扩展知识</span></h1>
  <p data-lake-id="u31ea1ce1" id="u31ea1ce1"><br></p>
  <h2 data-lake-id="oQqUC" id="oQqUC"><span data-lake-id="uae5ed3cb" id="uae5ed3cb">使用</span></h2>
  <p data-lake-id="ud71e2913" id="ud71e2913"><br></p>
  <p data-lake-id="u5cc19f9d" id="u5cc19f9d"><span data-lake-id="u50cbfeba" id="u50cbfeba">想要学习一个命令，先来看看帮助，使用jstack -help查看帮助：</span></p>
  <pre lang="java"><code>
hollis@hos:~$ jstack -help
Usage:
    jstack [-l] &lt;pid&gt;
        (to connect to running process)
    jstack -F [-m] [-l] &lt;pid&gt;
        (to connect to a hung process)
    jstack [-m] [-l] &lt;executable&gt; &lt;core&gt;
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]&lt;remote server IP or hostname&gt;
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack &lt;pid&gt; does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message
</code></pre>
  <p data-lake-id="u48fa34a8" id="u48fa34a8"><br></p>
  <p data-lake-id="u27ee2649" id="u27ee2649"><span data-lake-id="u139f9c33" id="u139f9c33">-F当’jstack [-l] pid’没有响应的时候强制打印栈信息 -l长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表. -m打印java和native c/c++框架的所有栈信息. -h | -help打印帮助信息 pid 需要被打印配置信息的java进程id,可以用jps查询.</span></p>
  <p data-lake-id="u54811601" id="u54811601"><span data-lake-id="ued16dc71" id="ued16dc71">​</span><br></p>
  <p data-lake-id="u7d860345" id="u7d860345"><span data-lake-id="u77472eda" id="u77472eda">首先，我们分析这么一段程序的线程情况：</span></p>
  <pre lang="java"><code>
/**
 * @author hollis
 */
public class JStackDemo1 {
    public static void main(String[] args) {
        while (true) {
            //Do Nothing
        }
    }
}
</code></pre>
  <p data-lake-id="u93ae7c02" id="u93ae7c02"><br></p>
  <p data-lake-id="u302a9ddd" id="u302a9ddd"><span data-lake-id="u4b453a4d" id="u4b453a4d">先是用jps查看进程号：</span></p>
  <pre lang="java"><code>
hollis@hos:~$ jps
29788 JStackDemo1
29834 Jps
22385 org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
</code></pre>
  <p data-lake-id="u3c3b38db" id="u3c3b38db"><br></p>
  <p data-lake-id="uea4e54f8" id="uea4e54f8"><span data-lake-id="uec0917fe" id="uec0917fe">然后使用jstack 查看堆栈信息：</span></p>
  <pre lang="java"><code>
hollis@hos:~$ jstack 29788
2015-04-17 23:47:31
...此处省略若干内容...
"main" prio=10 tid=0x00007f197800a000 nid=0x7462 runnable [0x00007f197f7e1000]
   java.lang.Thread.State: RUNNABLE
    at javaCommand.JStackDemo1.main(JStackDemo1.java:7)
</code></pre>
  <p data-lake-id="uc4c0bf00" id="uc4c0bf00"><br></p>
  <p data-lake-id="ub0d09f10" id="ub0d09f10"><span data-lake-id="u866d4b24" id="u866d4b24">我们可以从这段堆栈信息中看出什么来呢？我们可以看到，当前一共有一条用户级别线程,线程处于runnable状态，执行到JStackDemo1.java的第七行。 看下面代码：</span></p>
  <p data-lake-id="ua8bde9bf" id="ua8bde9bf"><span data-lake-id="u51a59458" id="u51a59458">​</span><br></p>
  <pre lang="java"><code>
/**
 * @author hollis
 */
public class JStackDemo1 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Thread1());
        thread.start();
    }
}
class Thread1 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println(1);
        }
    }
}
</code></pre>
  <p data-lake-id="u2e8e4215" id="u2e8e4215"><span data-lake-id="ubf8072bc" id="ubf8072bc">线程堆栈信息如下：</span></p>
  <p data-lake-id="u8c5293b4" id="u8c5293b4"><span data-lake-id="uec636991" id="uec636991">​</span><br></p>
  <pre lang="java"><code>
"Reference Handler" daemon prio=10 tid=0x00007fbbcc06e000 nid=0x286c in Object.wait() [0x00007fbbc8dfc000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on &lt;0x0000000783e066e0&gt; (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:503)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
    - locked &lt;0x0000000783e066e0&gt; (a java.lang.ref.Reference$Lock)
</code></pre>
  <p data-lake-id="u5d4ce625" id="u5d4ce625"><span data-lake-id="uad4167ab" id="uad4167ab">我们能看到：</span></p>
  <p data-lake-id="u9984d565" id="u9984d565"><span data-lake-id="u143167f9" id="u143167f9">​</span><br></p>
  <blockquote data-lake-id="u6b429a69" id="u6b429a69">
   <p data-lake-id="u2632b3c5" id="u2632b3c5"><span data-lake-id="uaac5b32b" id="uaac5b32b">线程的状态： WAITING 线程的调用栈 线程的当前锁住的资源： &lt;0x0000000783e066e0&gt; 线程当前等待的资源：&lt;0x0000000783e066e0&gt;</span></p>
  </blockquote>
  <p data-lake-id="ua34ba3a9" id="ua34ba3a9"><span data-lake-id="u80e70934" id="u80e70934">​</span><br></p>
  <p data-lake-id="u0e0c1055" id="u0e0c1055"><span data-lake-id="u634a5fbb" id="u634a5fbb">为什么同时锁住的等待同一个资源：</span></p>
  <p data-lake-id="ud36fa4b3" id="ud36fa4b3"><span data-lake-id="u3f18b5fb" id="u3f18b5fb">​</span><br></p>
  <blockquote data-lake-id="u45d4d1d0" id="u45d4d1d0">
   <p data-lake-id="ub28861a3" id="ub28861a3"><span data-lake-id="ubf210a05" id="ubf210a05">线程的执行中，先获得了这个对象的 Monitor（对应于 locked &lt;0x0000000783e066e0&gt;）。当执行到 obj.wait(), 线程即放弃了 Monitor的所有权，进入 “wait set”队列（对应于 waiting on &lt;0x0000000783e066e0&gt; ）。</span></p>
  </blockquote>
  <p data-lake-id="u172fc04d" id="u172fc04d"><br></p>
  <p data-lake-id="u3cbe2205" id="u3cbe2205"><span data-lake-id="ue069a8a4" id="ue069a8a4">​</span><br></p>
 </body>
</html>